// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab
/*
 * Ceph - scalable distributed file system
 *
 * Copyright (C) 2016 Red Hat
 *
 * This is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1, as published by the Free Software
 * Foundation.  See file COPYING.
 *
 */

#ifndef CEPH_CLIENT_USERPERM_H
#define CEPH_CLIENT_USERPERM_H

struct UserPerm
{
private:
    uid_t m_uid;
    gid_t m_gid;
    int gid_count;
    gid_t *gids;
    bool alloced_gids;
    void deep_copy_from(const UserPerm &b)
    {
        if (alloced_gids)
        {
            delete[] gids;
            alloced_gids = false;
        }
        m_uid = b.m_uid;
        m_gid = b.m_gid;
        gid_count = b.gid_count;
        if (gid_count > 0)
        {
            gids = new gid_t[gid_count];
            alloced_gids = true;
            for (int i = 0; i < gid_count; ++i)
            {
                gids[i] = b.gids[i];
            }
        }
    }

public:
    UserPerm() : m_uid(-1), m_gid(-1), gid_count(0), gids(NULL), alloced_gids(false) {}
    UserPerm(uid_t uid, gid_t gid, int ngids = 0, gid_t *gidlist = NULL) : m_uid(uid), m_gid(gid), gid_count(ngids),
                                                                           gids(gidlist), alloced_gids(false) {}
    UserPerm(const UserPerm &o) : UserPerm()
    {
        deep_copy_from(o);
    }
    UserPerm(UserPerm &&o)
    {
        m_uid = o.m_uid;
        m_gid = o.m_gid;
        gid_count = o.gid_count;
        gids = o.gids;
        alloced_gids = o.alloced_gids;
        o.gids = NULL;
        o.gid_count = 0;
    }
    ~UserPerm()
    {
        if (alloced_gids)
            delete[] gids;
    }
    UserPerm &operator=(const UserPerm &o)
    {
        deep_copy_from(o);
        return *this;
    }

    uid_t uid() const { return m_uid != (uid_t)-1 ? m_uid : ::geteuid(); }
    gid_t gid() const { return m_gid != (gid_t)-1 ? m_gid : ::getegid(); }
    bool gid_in_groups(gid_t id) const
    {
        if (id == gid())
            return true;
        for (int i = 0; i < gid_count; ++i)
        {
            if (id == gids[i])
                return true;
        }
        return false;
    }
    int get_gids(const gid_t **_gids) const
    {
        *_gids = gids;
        return gid_count;
    }
    void init_gids(gid_t *_gids, int count)
    {
        gids = _gids;
        gid_count = count;
        alloced_gids = true;
    }
    void shallow_copy(const UserPerm &o)
    {
        m_uid = o.m_uid;
        m_gid = o.m_gid;
        gid_count = o.gid_count;
        gids = o.gids;
        alloced_gids = false;
    }
};

#endif
